﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace SerialTool
{
    public partial class FormMain : Form
    {

        delegate void ShowFrameHandler(Frame frame);

        class FrameFilter : IFrameFilter
        {
            FormMain form;

            public FrameFilter(FormMain form)
            {
                this.form = form;
            }

            #region IFrameFilter 成员

            public bool Match(Frame frame)
            {
                return true;
            }

            public void AddFrame(Frame frame)
            {
                this.form.ShowFrame(frame);
            }

            public Frame GetFrame(int timeout)
            {
                return null;
            }

            #endregion
        }

        class ValCalFilter : IFrameFilter
        {
            FormValCal form;
            public ValCalFilter(FormValCal form)
            {
                this.form = form;
            }

            #region IFrameFilter 成员

            public bool Match(Frame frame)
            {
                return true;
            }

            public void AddFrame(Frame frame)
            {
                if (this.form != null && (this.form.IsDisposed == false))
                {
                    form.CalFrame(frame);
                }
            }

            public Frame GetFrame(int timeout)
            {
                return null;
            }

            #endregion
        }

        byte[] lastTxData;//len,src,srclen,tgt,tgtlen,type,cmd,data;

        SerialPort serialPort = new SerialPort();
        FrameManager frameManager;
        private long lastTick;
        int markNum = 0;

        public FormMain()
        {
            InitializeComponent();

            frameManager = new FrameManager(serialPort);

            frameManager.AddFilter(new FrameFilter(this));
            lastTick = DateTime.Now.Ticks;
        }

        public void ShowFrame(Frame frame)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new ShowFrameHandler(ShowFrame), new object[] { frame });
            }
            else
            {
                long tick = DateTime.Now.Ticks - lastTick;
                lastTick += tick;
                tick = (tick / 10000) > 99999 ? 99999 : (tick / 10000);
                textBoxRx.AppendText(tick.ToString().PadLeft(5) + ">RX:");

                textBoxRx.AppendText(changeForm(frame.ToStringX2(markNum)));
                textBoxRx.AppendText("\r\n");

                Thread.Sleep(int.Parse(textBox_ackDelay.Text));

                if (checkBox_autoAck.Checked)
                {
                    byte[] ack = autoAckDataPrepare(frame);
                    TransmiteFrame(ack);
                    if (ack != null)
                    {
                        long tick0 = DateTime.Now.Ticks - lastTick;
                        lastTick += tick0;
                        tick0 = (tick0 / 10000) > 99999 ? 99999 : (tick0 / 10000);
                        textBoxRx.AppendText(tick0.ToString().PadLeft(5) + ">TX:");

                        textBoxRx.AppendText(changeForm(bufToString(ack)));
                        textBoxRx.AppendText("\r\n");
                    }
                }
            }
        }

        //------------------------------------------------------------------------------------
        private byte[] autoAckDataPrepare(Frame frame)
        {
            byte[] ack = null;
            if (frame.SrcPort != 0x21)
                return null;

            //main A
            if (frame.DestPort == 0x30 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 68]{
                    0x30 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0x01 ,0x03 ,
                    0x00 ,0x01 ,0x00 ,0x00 ,0x00 ,0x80 ,0x01 ,0x01 ,
                    0x00 ,0x01 ,0xFE ,0xAD ,0x3A ,0x81 ,0x10 ,0x3A ,
                    0x09 ,0xF8 ,0x01 ,0x03 ,0x00 ,0x01 ,0x01 ,0x01 ,
                    0x00 ,0x00 ,0x00 ,0x00 ,0x3B ,0x44 ,0x1F ,0x06 ,
                    0x02 ,0x01 ,0x20 ,0x4E ,0x08 ,0x04 ,0x07 ,0x00 ,
                    0x00 ,0xC8 ,0x01 ,0x03 ,0x00 ,0x01 ,0x01 ,0x01 ,
                    0x00 ,0x00 ,0x00 ,0x00 ,0x3B ,0x44 ,0x2F ,0x06 ,
                    0x02 ,0x01 ,0x20 ,0x4E ,0x08 ,0x04 ,0x07 ,0x00 ,
                    0x00 ,0xC8};
            /*
             * 00 4C 30 00 21 00 04 17 01 03 00 01 00 00 00 80 01 01 00 01 FE AD 3A 81 10 3A 09 F8 01 03 00 01 01 01 00 00 00 00 3B 44 1F 06 02 01 20 4E 08 04 07 00 00 C8 01 03 00 01 01 01 00 00 00 00 3B 44 2F 06 02 01 20 4E 08 04 07 00 00 C8
            */

            //JMA1 
            if (frame.DestPort == 0x31 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 28]{
                    0x31 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0xAA ,0xAA ,
                    0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,
                    0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,
                    0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,
                    0xAA ,0xAA };
            //JMA2
            if (frame.DestPort == 0x32 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 28]{
                    0x32 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0xBB ,0xBB ,
                    0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,
                    0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,
                    0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,0xBB ,
                    0xBB ,0xBB };

            //mian B
            if (frame.DestPort == 0x40 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 68]{
                    0x40 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0x01 ,0x03 ,
                    0x00 ,0x01 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x01 ,
                    0x00 ,0x00 ,0xFE ,0xAD ,0x3A ,0x01 ,0x10 ,0xBA ,
                    0x09 ,0xF8 ,0x01 ,0x03 ,0x00 ,0x01 ,0x01 ,0x01 ,
                    0x00 ,0x00 ,0x00 ,0x00 ,0x3B ,0x44 ,0x36 ,0x06 ,
                    0x02 ,0x01 ,0x20 ,0x4E ,0x08 ,0x04 ,0x05 ,0x00 ,
                    0x00 ,0xC8 ,0x01 ,0x03 ,0x00 ,0x01 ,0x01 ,0x01 ,
                    0x00 ,0x00 ,0x00 ,0x00 ,0x3B ,0x44 ,0x2A ,0x06 ,
                    0x02 ,0x01 ,0x1F ,0x4E ,0x07 ,0x04 ,0x06 ,0x00 ,
                    0x00 ,0xC8};

            /*
             * 00 4C 40 00 21 00 04 17 01 03 00 01 00 00 00 00 00 01 00 00 FE AD 3A 01 10 BA 09 F8 01 03 00 01 01 01 00 00 00 00 3B 44 36 06 02 01 20 4E 08 04 05 00 00 C8 01 03 00 01 01 01 00 00 00 00 3B 44 2A 06 02 01 1F 4E 07 04 06 00 00 C8
            */

            //JMB1 
            if (frame.DestPort == 0x41 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 28]{
                    0x41 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0xCC ,0xCC ,
                    0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,
                    0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,
                    0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,0xCC ,
                    0xCC ,0xCC };
            //JMB2
            if (frame.DestPort == 0x42 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
                ack = new byte[6 + 28]{
                    0x42 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0xDD ,0xDD ,
                    0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,
                    0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,
                    0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,0xDD ,
                    0xDD ,0xDD  };

            ////LJB
            //if (frame.DestPort == 0x50 && frame.cmdType == 0x04 && frame.Cmd == 0x16)
            //    //ack = new byte[6 + 18]{
            //    //    0x50 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0x06,0x06 ,
            //    //    0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06,
            //    //    0x08 ,0x09 ,0x02 ,0x02 ,0x02 ,0x02 ,0x06 ,0x06};
            //    ack = new byte[6 + 26]{
            //        0x50 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0x88 ,0x88 ,
            //        0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,
            //        0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,
            //        0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 ,0x88 };

            
            ////JLB
            //if (frame.DestPort == 0x20 && frame.cmdType == 0x04 && frame.Cmd == 0x3A)
            //    //ack = new byte[6 + 18]{
            //    //    0x50 ,0x00 ,0x21 ,0x00 ,0x04 ,0x17 ,0x06,0x06 ,
            //    //    0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06 ,0x06,
            //    //    0x08 ,0x09 ,0x02 ,0x02 ,0x02 ,0x02 ,0x06 ,0x06};
            //    ack = new byte[6 + 2]{
            //        0x20 ,0x00 ,0x21 ,0x00 ,0x04 ,0x3E ,0x3A ,0x00 };
            

            return ack;
        }

        private string bufToString(byte[] data)
        {
            if (data == null)
                return null;

            StringBuilder sb = new StringBuilder();
            byte[] len = new byte[2];
            len[0] = (byte)(((data.Length+2)>>8) & 0xFF);
            len[1] = (byte)(((data.Length+2)>>0) & 0xFF);

            for (int i = 0; i < len.Length; i++)
            {
                sb.Append(len[i].ToString("X2") + " ");
            }

            for (int i = 0; i < data.Length; i++)
            {
                sb.Append(data[i].ToString("X2") + " ");
            }
            string str = "10 02 " + sb.ToString() +"10 03";
            return str;
        }

        private string changeForm(string str)
        {
            string formStr = "";
            int len = 32 * 3;
            while (str.Length > len)
            {
                formStr += str.Substring(0, len);
                formStr += "\r\n";
                formStr += "         ";
                str = str.Substring(len);
            }
            formStr += str;
            return formStr;
        }

        //-------------------------------------
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            FormValCal formVal = new FormValCal();
            formVal.Owner = this;
            formVal.Show();
            frameManager.AddFilter(new ValCalFilter(formVal));
        }

        private byte[] PrepareData()
        {
            int txLength = 0;
            byte[] txData = new byte[2048];//len,src,srclen,tgt,tgtlen,type,cmd,data;
            txData[0] = byte.Parse(textBox2.Text, System.Globalization.NumberStyles.AllowHexSpecifier); //源端口 (测试仪)
            txData[1] = 0;//源地址长度
            txData[2] = byte.Parse(textBox3.Text, System.Globalization.NumberStyles.AllowHexSpecifier); //目的端口号 (记录板)
            txData[3] = 0; //目的地址长度

            txData[4] = byte.Parse(textBox4.Text, System.Globalization.NumberStyles.AllowHexSpecifier);//业务类型
            txData[5] = byte.Parse(textBox5.Text, System.Globalization.NumberStyles.AllowHexSpecifier);//命令


            string[] dataStr = textBox6.Text.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < dataStr.Length; i++)
            {
                txData[6 + i] = byte.Parse(dataStr[i], System.Globalization.NumberStyles.AllowHexSpecifier);
            }

            txLength = 6 + dataStr.Length;

            byte[] buf = new byte[txLength];

            Array.Copy(txData, 0, buf, 0, txLength);
            return buf;
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                lastTxData = PrepareData();
                timer1.Interval = int.Parse(textBox1.Text);
                timer1.Enabled = true;
                buttonSend.Enabled = false;
            }
            else
            {
                timer1.Enabled = false;
                buttonSend.Enabled = true;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            TransmiteFrame(lastTxData);
        }

        private byte[] TransmiteFrame(byte[] data )
        {
            byte[] txBuffer = new byte[2048];
            if (data == null)
                return null;
            int length = data.Length;

            if (length <= 0) return null;
            int dataLen = length + 2;


            //计算CRC
            txBuffer[0] = (byte)((dataLen >> 8) & 0xff);
            txBuffer[1] = (byte)(dataLen & 0xff);

            for (int i = 0; i < length; i++)
            {
                txBuffer[i + 2] = data[i];
            }

            UInt16 crc = CRC16.ComputeCRC16(txBuffer, 0, dataLen);

            int index = 0;

            //帧头
            txBuffer[index] = 0x10;
            index++;
            txBuffer[index] = 0x02;
            index++;


            //数据长度
            txBuffer[index] = (byte)((dataLen >> 8) & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            txBuffer[index] = (byte)(dataLen & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            //数据
            for (int i = 0; i < length; i++)
            {
                txBuffer[index] = data[i];
                index++;
                if (txBuffer[index - 1] == 0x10)
                {
                    txBuffer[index] = 0x10;
                    index++;
                }
            }
            //CRC
            txBuffer[index] = (byte)((crc >> 8) & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            txBuffer[index] = (byte)(crc & 0xff);
            index++;
            if (txBuffer[index - 1] == 0x10)
            {
                txBuffer[index] = 0x10;
                index++;
            }
            //帧尾
            txBuffer[index] = 0x10;
            index++;
            txBuffer[index] = 0x03;
            index++;

            if (serialPort.IsOpen)
            {
                try
                {
                    //发送数据
                    serialPort.Write(txBuffer, 0, index);
                }
                catch (Exception) { }
            }
            byte[] tmp = new byte[index];
            Array.Copy(txBuffer, tmp, index);
            return tmp;
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            lastTxData = PrepareData();

            TransmiteFrame(lastTxData);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            getPorts();

            groupBox1.Enabled = false;
        }

        private void getPorts()
        {
            toolStripComboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            toolStripComboBox1.Items.Clear();

            string[] ports = SerialPort.GetPortNames();
            if (ports != null)
            {
                for (int i = 0; i < ports.Length; i++)
                {
                    toolStripComboBox1.Items.Add(ports[i]);
                }
            }
            if (toolStripComboBox1.Items.Count > 0)
            {
                toolStripComboBox1.SelectedIndex = 0;
            }

            toolStripComboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
            toolStripComboBox2.Items.Clear();

            if (ports != null)
            {
                toolStripComboBox2.Items.Add("115200");
                toolStripComboBox2.Items.Add("9600");
            }
            if (toolStripComboBox2.Items.Count > 0)
            {
                toolStripComboBox2.SelectedIndex = 0;
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                try
                {
                    serialPort.Close();
                    buttonStart.Text = "打开";
                    toolStripComboBox1.Enabled = true;
                    toolStripComboBox2.Enabled = true;
                    buttonStart.Image = Properties.Resources.Play;
                    groupBox1.Enabled = false;
                }
                catch { }
            }
            else
            {
                try
                {
                    serialPort.PortName = toolStripComboBox1.Text;
                    serialPort.BaudRate = int.Parse(toolStripComboBox2.Text);
                    serialPort.Open();
                    buttonStart.Text = "关闭";
                    toolStripComboBox1.Enabled = false;
                    toolStripComboBox2.Enabled = false;
                    buttonStart.Image = Properties.Resources.Stop;
                    groupBox1.Enabled = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxRx.Clear();
        }

        private void toolStripComboBox1_DropDown(object sender, EventArgs e)
        {
            getPorts();
        }

        private void checkBox_autoAck_CheckedChanged(object sender, EventArgs e)
        {
            textBox_ackDelay.Enabled = !textBox_ackDelay.Enabled;
        }

        //-------------------------------------------------------------------------
        private void textBox_mark_KeyPress(object sender, KeyPressEventArgs e)
        {
            #region 不是Enter键返回
            if (e.KeyChar != 13 )   // != Enter
            {
                return;
            }
            #endregion

            e.Handled = true;
            string srcText = textBox_input.Text;

            #region command "send"
            if (textBox_input.Text.Trim() == "send")
            {
                textBox_input.SelectionStart = 0;
                textBox_input.SelectionLength = textBox_input.Text.Length;
                lastTxData = PrepareData();
                TransmiteFrame(lastTxData);
            }
            #endregion
            #region command "mark"
            else if (textBox_input.Text.Trim().StartsWith("mark"))
            {
                try
                {
                    markNum = int.Parse(textBox_input.Text.Trim().Substring(4));
                }
                catch
                {
                }
                textBox_input.SelectionStart = 0;
                textBox_input.SelectionLength = textBox_input.Text.Length;
            }
            #endregion
            #region command "list"
            else if (textBox_input.Text.Trim().StartsWith("list"))
            {
                string[] you = LrnS.GetAllItemNameGrep(textBox_input.Text.Substring(4).Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries));

                if (you.Length > 0)
                {
                    for (int i = 0; i < you.Length; i++)
                    {
                        textBoxRx.AppendText(you[i]);
                        textBoxRx.AppendText("\r\n");
                    }
                }
                textBox_input.SelectionStart = 0;
                textBox_input.SelectionLength = textBox_input.Text.Length;
            }
            #endregion
            #region command "clear"
            else if (textBox_input.Text.Trim() == "clear")
            {
                textBoxRx.Clear();
                textBox_input.SelectionStart = 0;
                textBox_input.SelectionLength = textBox_input.Text.Length;
            }
            #endregion
            #region 把提示中的命令放到文本框中
            else if (textBox_input.SelectionLength != 0)
            {
                int start = textBox_input.SelectionStart;

                textBox_input.Text = textBox_input.Text.Substring(start, textBox_input.SelectionLength);

                textBox_input.SelectionStart = textBox_input.Text.Length;
                textBox_input.SelectionLength = 0;
            }
            #endregion
            #region command "setcmd"
            else if (srcText.StartsWith("setcmd"))
            {
                string str = textBox2.Text + " " + textBox3.Text + " " + textBox4.Text +
                    " " + textBox5.Text + " " + textBox6.Text;

                LrnS.SaveItem("cmd" + srcText.Substring(6), str);
                textBox_input.Text = "";
            }
            #endregion
            #region read out Lrns
            else if (srcText.StartsWith("cmd"))
            {
                string cmdstr = LrnS.GetItem(srcText);
                string[] dataStr = cmdstr.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

                if (dataStr != null)
                {
                    textBox2.Text = dataStr[0]; //源端口 (测试仪)

                    textBox3.Text = dataStr[1]; //目的端口号 (记录板)

                    textBox4.Text = dataStr[2];//业务类型
                    textBox5.Text = dataStr[3];//命令
                    textBox6.Text = "";
                    for (int i = 4; i < dataStr.Length; i++)
                    {
                        textBox6.Text += dataStr[i] + " ";
                    }
                    string str = textBox2.Text + " " + textBox3.Text + " " + textBox4.Text +
                    " " + textBox5.Text + " " + textBox6.Text;

                    LrnS.SaveItem(srcText, str);
                    textBox_input.Text = "";
                }
            }
            #endregion
            else
            {
                //nothing to do here.
            }
        }
        private void textBox_mark_KeyUp(object sender, KeyEventArgs e)
        {
            #region key "Backspace"
            if (e.KeyValue == 0x08)         // == Backspace
            {
                int start = textBox_input.SelectionStart;
                if (start > 0)
                    start--;

                textBox_input.Text = textBox_input.Text.Substring(0, start);
                if (textBox_input.Text == "")
                    return;
                string[] you = LrnS.GetAllItemNameGrep(textBox_input.Text.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries));
                
                if (you.Length > 0)
                {
                    textBox_input.Text += you[0];
                    textBox_input.SelectionLength = you[0].Length;
                }
                else
                {
                    textBox_input.SelectionLength = 0;
                }
                textBox_input.SelectionStart = start;
            }
            #endregion
            #region key "a-z A-Z 0-9" and ";" and "space"
            else if (
                (e.KeyValue >= 'A' && e.KeyValue <= 'Z')
                    ||
                (e.KeyValue >= 'a' && e.KeyValue <= 'z')
                    ||
                (e.KeyValue >= '0' && e.KeyValue <= '9')
                    ||
                (e.KeyValue == 0x20)
                    ||
                (e.KeyValue == ';')
                )
            {
                int start = textBox_input.SelectionStart;

                textBox_input.Text = textBox_input.Text.Substring(0, start);

                string[] you = LrnS.GetAllItemNameGrep(textBox_input.Text.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries));

                string firstone = "";
                if (you.Length > 0)
                    firstone = you[0];
                textBox_input.Text += firstone;
                textBox_input.SelectionStart = start;
                textBox_input.SelectionLength = firstone.Length;
            }
            #endregion
            else
            {
                //nothing to do here
            }
        }
        private void textBox_input_Leave(object sender, EventArgs e)
        {
            int start = textBox_input.SelectionStart;
            textBox_input.Text = textBox_input.Text.Substring(0, start);
        }
        
    //-----------------------------------------------------------------------------
    }
}
